﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Diagnostics;

namespace PWAsker
{
    /// <summary>
    /// Interaction logic for ConfigurationWnd.xaml
    /// </summary>
    public partial class ConfigurationWnd : Window
    {
        const String ADD_ITEM = "<<<add>>>";

        private ObservableCollection<Executable> lTmpExecutables;
        private List<Executable> lOrigExecutables;

        private Configuration config;

        private Boolean save = false;
        private Boolean discard = false;

        //Holds information if cofiguration has been changed
        private Boolean ConfigurationChanged = false;

        public ConfigurationWnd(List<Executable> executables, Configuration config)
        {
            lOrigExecutables = executables;
            lTmpExecutables = new ObservableCollection<Executable>(copyExecutables(executables));
            this.config = config;

            InitializeComponent();

            //Initilizing Menu
            MenuItem_EnableExitOnSucessfulExecution.IsChecked = config.EndOnSucessfullExecute;

            //adding virtual item for add
            lTmpExecutables.Add(new Executable(ADD_ITEM, false, 0));

            //set up binding
            stringList.DataContext = lTmpExecutables;            
        }

        private void stringList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

            if (stringList.SelectedIndex == -1)
            {
                Debug.WriteLine("Refusing to set Editbox.Text to Vaue from Inavild Item " + stringList.SelectedIndex);
                editBox.IsEnabled = false;
            }
            else
            {
                Debug.WriteLine("Item no. " + stringList.SelectedIndex + " loaded to editbox");
                editBox.Text = stringList.SelectedItem.ToString();
                
                if (editBox.IsEnabled == false)
                {
                    editBox.IsEnabled = true;
                }
            }
        editBox.Focus();
        }

        private void editBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (stringList.SelectedIndex == -1)
            {
                Debug.WriteLine("Refusing to update invalid list-item no. " + stringList.SelectedIndex);
            }
            else
            {
                int selection = stringList.SelectedIndex;
                Debug.WriteLine("Replacing Element " + selection + ": " + lTmpExecutables.ElementAt(selection) + " with " + editBox.Text);

                lTmpExecutables[selection].ExecCommand = editBox.Text;

                //setting selected item back to the item the user selected
                //it is resetted to -1 through rewriting the element with "lTmpExecutables[selection] = editBox.Text;"
                stringList.SelectedIndex = selection;
            }
            
        }

        private void buttonSave_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Save-Button clicked");
            save = true;
            Close();
        }

        private void buttonCancel_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Cancel-Button clicked");
            discard = true;
            Close();
        }

        private void Configuration_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (contentEquals(lOrigExecutables.ToList<Executable>(), lTmpExecutables.ToList<Executable>()))
            {
                Debug.WriteLine("Nothing changed, leaving window without user-request");
            }
            else
            {
                Debug.Write("Changes detected - ");
                if (save == discard)
                {
                    Debug.Write("asking user what to do\r\n");

                    MessageBoxResult mbrSaveChanges = MessageBox.Show("Do you want to save the changed made to the configuration?", "unsaved changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);

                    if (mbrSaveChanges== MessageBoxResult.Yes)
                    {
                        Debug.WriteLine("User wants to close saving changes");
                        saveChanges();
                    }
                    else if (mbrSaveChanges == MessageBoxResult.Cancel)
                    {
                        Debug.WriteLine("User cancelled closing");
                        e.Cancel = true;
                    }
                    else if (mbrSaveChanges == MessageBoxResult.No)
                    {
                        Debug.WriteLine("User wants to close discarding changes");
                    }
                }
                else if (save == true)
                {
                    Debug.Write("saving changes\r\n");
                    saveChanges();
                }
                else if (discard == true)
                {
                    Debug.Write("discarding changes\r\n");
                }
            }  
        }

        private void saveChanges()
        {
            lOrigExecutables.Clear();
            
            for(int i = 0; i<lTmpExecutables.Count; i++)
            {
                //ignoring vitual "add"-items
                if (lTmpExecutables.ElementAt(i).ExecCommand != ADD_ITEM)
                {
                    lOrigExecutables.Add(lTmpExecutables.ElementAt(i));
                    lOrigExecutables.Last<Executable>().WaitForCommand = lTmpExecutables.ElementAt(i).WaitForCommand;
                    lOrigExecutables.Last<Executable>().WaitSecs = lTmpExecutables.ElementAt(i).WaitSecs;
                }
            }
            ConfigurationChanged = true;
            Debug.WriteLine("Changes saved");
        }

        public Boolean madeChanges()
        {
            return ConfigurationChanged;
        }

        private Boolean contentEquals(List<Executable> ExecList1, List<Executable> ExecList2)
        {
            //remove vitual "add"-items
            for (int i = 0; i < ExecList1.Count; i++)
            {
                if (ExecList1.ElementAt(i).ExecCommand == ADD_ITEM)
                {
                    ExecList1.RemoveAt(i);
                    i--;
                }
            }
            for (int i = 0; i < ExecList2.Count; i++)
            {
                if (ExecList2.ElementAt(i).ExecCommand == ADD_ITEM)
                {
                    ExecList2.RemoveAt(i);
                    i--;
                }
            }

            if (ExecList1.Count == ExecList2.Count)
            {
                for (int i = 0; i < ExecList1.Count; i++)
                {
                    if (Executable.compare(ExecList1[i], ExecList2[i]) == false)
                    {
                        return false;
                    }
                }
            }
            else
            {
                return false;
            }
            return true;
        }

        private void editBox_GotFocus(object sender, RoutedEventArgs e)
        {
            if (editBox.Text == ADD_ITEM)
            {
                //saving last selection
                int selection = stringList.SelectedIndex;

                //clearing ADD_ITEM-content
                editBox.Clear();
                lTmpExecutables[selection].ExecCommand = String.Empty;

                //add new ADD_ITEM
                lTmpExecutables.Add(new Executable(ADD_ITEM, false, 0));
                
                //setting back selection
                stringList.SelectedIndex = selection;
            }
        }

        //removes empty elements from the list-object
        private void cropList(ref ObservableCollection<Executable> ExecList)
        {
            for (int i = 0; i < ExecList.Count; i++)
            {
                if (ExecList.ElementAt(i).ExecCommand == String.Empty)
                {
                    ExecList.RemoveAt(i);
                    i--;
                }
            }
        }

        private void editBox_LostFocus(object sender, RoutedEventArgs e)
        {
            cropList(ref lTmpExecutables);
        }

        private void contextMenu_Add(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Adding item at" + stringList.SelectedIndex);

            lTmpExecutables.Insert(stringList.SelectedIndex, new Executable(String.Empty, false, 0));

            //focus newly created item on stringList
            stringList.SelectedIndex = stringList.SelectedIndex - 1;
        }

        private void contextMenu_Remove(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Removing item " + stringList.SelectedIndex);

            lTmpExecutables.RemoveAt(stringList.SelectedIndex);
            editBox.Clear();
        }

        private void contextMenu_Properties(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Opening properties for item #" + stringList.SelectedIndex + " by contextmenu. Dump:");
            Debug.WriteLine(lTmpExecutables.ElementAt(stringList.SelectedIndex).ExecCommand + " - " + lTmpExecutables.ElementAt(stringList.SelectedIndex).WaitForCommand + " - " + lTmpExecutables.ElementAt(stringList.SelectedIndex).WaitSecs);

            PropertiesWnd properties = new PropertiesWnd(lTmpExecutables.ElementAt(stringList.SelectedIndex));
            properties.Owner = this;
            properties.ShowDialog();
        }

        private void stringList_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            Debug.WriteLine("Opening properties for item #" + stringList.SelectedIndex + " by double-mouse-click Dump:");
            Debug.WriteLine(lTmpExecutables.ElementAt(stringList.SelectedIndex).ExecCommand + " - " + lTmpExecutables.ElementAt(stringList.SelectedIndex).WaitForCommand + " - " + lTmpExecutables.ElementAt(stringList.SelectedIndex).WaitSecs);

            PropertiesWnd properties = new PropertiesWnd(lTmpExecutables.ElementAt(stringList.SelectedIndex));
            properties.Owner = this;
            properties.ShowDialog();
        }

        private void stringList_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            if(editBox.Text == String.Empty)
            {
                Debug.WriteLine("Supressing context menu on add-metaelement");
                e.Handled = true;
            }
        }

        //copying all executables in the list by value
        private List<Executable> copyExecutables(List<Executable> lSrc)
        {
            List<Executable> lDst = new List<Executable>();
            for (int i = 0; i < lSrc.Count; i++)
            {
                lDst.Add(new Executable(lSrc[i].ExecCommand, lSrc[i].WaitForCommand, lSrc[i].WaitSecs));
            }
            return lDst;
        }

        private void MenuItem_EnableExitOnSucessfulExecution_Unchecked(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Unchecked EndOnSucessfullExecute");
            config.EndOnSucessfullExecute = false;
            ConfigurationChanged = true;
        }

        private void MenuItem_EnableExitOnSucessfulExecution_Checked(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Checked EndOnSucessfullExecute");
            config.EndOnSucessfullExecute = true;
            ConfigurationChanged = true;
        }
    }
}
